package main

import (
	"fmt"
	"github.com/coreos/etcd/clientv3"
	"golang.org/x/net/context"
	"log"
	"time"
)

/**
https://blog.csdn.net/liangzhiyang/article/details/65633960
是对于WithTimeout(或者WithDeadline) 有两种情况
1. 一种是发生超时了，这个时候cancel 会自动调用，资源被释放
2. 另一种没有发生超时，也就是slowOperation结束的时候，这个时候需要咱们主动调用cancel；但是即使没有调用，在过期时间到了的时候还是会调用cancel，释放资源

所以：cancel 即使不主动调用，也不影响资源的最终释放，但是提前主动调用，可以尽快的释放，避免等待过期时间之间的浪费；
建议还是按照官方的说明使用，养成良好的习惯，在调用WithTimeout之后defer cancel()
————————————————

*/

func main() {
	//创建链接
	cv, err := clientv3.New(clientv3.Config{
		Endpoints:   []string{"192.168.0.104:2379"},
		DialTimeout: 100 * time.Second,
	})
	if err != nil {
		fmt.Println("connect to etcd failed, err:%v\n", err)
		return
	}
	fmt.Println("connect to etcd success")
	defer cv.Close()

	//lease租约
	resp1, err := cv.Grant(context.TODO(), 5) //创建一个五秒的租约
	if err != nil {
		log.Fatal(err)
	}
	// 5秒钟之后, /lmh/ 这个key就会被移除
	_, err = cv.Put(context.TODO(), "lmh", "lmh", clientv3.WithLease(resp1.ID))
	if err != nil {
		log.Fatal(err)
	}
	//keepalive
	ch, kaerr := cv.KeepAlive(context.TODO(), resp1.ID)
	if kaerr != nil {
		log.Fatal(kaerr)
	}
	for {
		ka := <-ch //把管道的数据传输给ka
		fmt.Println("ttl", ka.TTL)
	}

	//put操作
	/**
	上层需要指定超时的情况: ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
	上层需要主动取消的情况：ctx, cancel := context.WithCancel(ctx)；需要的地方调用cancel()
	节省资源
	*/
	ctx, cnacel := context.WithTimeout(context.Background(), time.Second)
	_, err = cv.Put(ctx, "lmh", "lmh")
	cnacel()
	if err != nil {
		fmt.Printf("put to etcd failed, err:%v\n", err)
		return
	}
	//get
	ctx, cancel1 := context.WithTimeout(context.Background(), time.Second)
	resp, err := cv.Get(ctx, "lmh")
	cancel1()
	if err != nil {
		fmt.Printf("get from etcd failed, err:%v\n", err)
		return
	}
	for _, ev := range resp.Kvs {
		fmt.Printf("%s:%s\n", ev.Key, ev.Value)
	}

	//watch操作
	watchchan := cv.Watch(ctx, "lmh") //// <-chan WatchResponse
	for wresp := range watchchan {
		for _, evc := range wresp.Events {
			fmt.Printf("%s:%s\n", evc.Type, evc.Kv.Key, evc.Kv.Value)
		}

	}

}
